<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-touch-fullscreen" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <title>learn-PixiJS</title>
</head>
<body>

<div>
    <button onclick="startPlay()">开始播放</button>
    <button onclick="playContinue()">继续播放视频</button>
    <button onclick="stopPlay()">暂停播放</button>
</div>
<div>

</div>
<script src="js/pixi.min.js"></script>

<script>

  const fragmentSrc_origin = `
 precision mediump float;

 // the texCoords passed in from the vertex shader.
 varying vec2 v_texCoord;

 // our texture
 uniform sampler2D uSampler2;

 void main(){
   // Look up a color from the texture.
   gl_FragColor = texture2D(uSampler2, v_texCoord).rgba;
 }
`;
  // 片段着色起
  let fragmentSrc = fragmentSrc_origin;
  let uniforms_steps = [];


  const Loader = PIXI.Loader.shared,
    Resources = PIXI.loader.resources,
    TextureCache = PIXI.utils.TextureCache;


  const videoUrl = 'media/video.mp4';
  const imgUrl = 'images/vocaloid.jpg';
  let videoTexture = null; // 视频纹理

  const global = {
    timer: null
  };


  var App = {
    geometry: null,
    startTime: null,
    textTextureArr: [], // 文字纹理数组
    init: function () {
      const picArr = [];

      picArr.push(videoUrl);
      picArr.push(imgUrl);
      for (let i = 0; i < 71; i++) {
        const texture = (`images/1X1/S1a_${i}.png`);
        picArr.push(texture);
      }
      for (let i = 0; i < 63; i++) {
        const texture = (`images/1X1/S1b_${i}.png`);
        picArr.push(texture);
      }
      for (let i = 0; i < 15; i++) {
        const texture = (`images/1X1/S1c_${i}.png`);
        picArr.push(texture);
      }

      window.app = new PIXI.Application({
        backgroundColor: 0x1099bb,
        width: 540,
        height: 540,
      });
      document.body.appendChild(app.view);

      // 加载资源
      Loader
        .add(picArr)
        .on("progress", this.loadProgressHandler)
        .load(this.onAssetsLoaded.bind(this));
      app.ticker.add((delta) => {


        const startTime = this.startTime;
        if (startTime) {
          const now = new Date().getTime();
          const currentTime = now - startTime;
          this.refreshView(currentTime)
        }

      });
    },
    // 资源加载进度
    loadProgressHandler: function (loader, resources) {
      console.log('loading progress: ', loader.progress.toFixed(2) / 1)
    },
    // 资源加载完毕
    onAssetsLoaded: function (loader, resources) {
      console.log("All files loaded");
      this.createVideoTexture();
    },
    // 刷新视图 全部数据
    refreshView: function (currentTime) {
      console.log(currentTime);
      this.refreshView_bg(currentTime);
      this.refreshTexts(currentTime);
    },
    // 刷新背景图 视频 / 图片
    refreshView_bg: function (currentTime) {
//      videoTexture = TextureCache[videoUrl]; // 暂时没有视频缓存
//      videoTexture.baseTexture.source.currentTime = currentTime / 1000;
//      videoTexture.update();

    },
    // 刷新文字
    refreshTexts: function (currentTime) {
      const textTextureArr = this.textTextureArr;
      for (let i = 0; i < textTextureArr.length; i++) {
        const textTexture = textTextureArr[i];
//        console.log(textTexture, 'textTexture');
        textTexture.refreshView(currentTime);
      }
    },
    // 创建视频纹理
    createVideoTexture: function () {
      videoTexture = PIXI.Texture.from(videoUrl, {autoPlay: false})
    },
    // 开始播放
    startPlay: function () {
      this.startTime = new Date().getTime();
//      app.stage.removeChildren();
      this.geometry = this.createGeometry();

      videoTexture = TextureCache[videoUrl]; // 从缓存中取出纹理
      videoTexture.baseTexture.source.currentTime = 0;
      videoTexture.baseTexture.source.play();
//      const videoSprite = new PIXI.Sprite(videoTexture);
//      videoSprite.width = app.screen.width;
//      videoSprite.height = app.screen.height;
//      app.stage.addChild(videoSprite);

      const anim = this.createImages();
      anim.play();
      app.stage.addChild(this.geometry);


      const text = createText({
        "textType": 4,
      });
      this.textTextureArr.push(text);

      const text1 = createText({
        "textType": 1,
      });
      this.textTextureArr.push(text1);
//      const text = this.createText();


//      text.height = 0;


      app.stage.addChild(anim);
      app.stage.addChild(text.contain);
      app.stage.addChild(text1.contain);

      global.timer = setTimeout(() => {
        anim.stop();
        this.stopPlay();
      }, 6000);

    },
    stopPlay: function () {
      this.startTime = null;
      videoTexture = TextureCache[videoUrl];
      if (videoTexture) {
        videoTexture.baseTexture.source.pause();
        videoTexture.update();
      }
    },
    createImages: function () {
      const frames = [];

      for (let i = 0; i < 71; i++) {
        const texture = TextureCache[`images/1X1/S1a_${i}.png`];
        frames.push(texture);
      }
      for (let i = 0; i < 63; i++) {
        const texture = TextureCache[`images/1X1/S1b_${i}.png`];
        frames.push(texture);
      }
      for (let i = 0; i < 15; i++) {
        const texture = TextureCache[`images/1X1/S1c_${i}.png`];
        frames.push(texture);
      }
      const anim = new PIXI.AnimatedSprite(frames);
      anim.x = 0;
      anim.y = 0;
//    anim.anchor.set(0.5); // 原点
      anim.animationSpeed = 0.4; // 速度 24 / 60 = 0.4
      return anim
    },
    createText: function () {
      const style = new PIXI.TextStyle({
        fontFamily: 'Arial',
        fontSize: 36,
//      fontStyle: 'italic',
        fontWeight: 'bold',
//        fill: ['#ffffff', '#00ff99'], // gradient
        fill: ['#ffffff'], // gradient
//        stroke: '#4a1850',
//        strokeThickness: 5,
//        dropShadow: true,
//        dropShadowColor: '#000000',
//        dropShadowBlur: 4,
//        dropShadowAngle: Math.PI / 6,
//        dropShadowDistance: 6,
        wordWrap: true,
        wordWrapWidth: 440,
      });

      const richText = new PIXI.Text('挑战你的极限', style);

      const container_x = (app.screen.width - richText.width) / 2;
      const container_y = 200;
      richText.x = 0;
      richText.y = -richText.height;
      let container = new PIXI.Container();
      container.addChild(richText);
      container.x = container_x;
      container.y = container_y;

      const timer = setInterval(() => {
        richText.y = richText.y + 2;
        if (richText.y > 0) {
          clearInterval(timer)
        }
      }, 70);


      const graphics = new PIXI.Graphics();
      graphics.beginFill(0xFF3300);
      graphics.drawRect(container_x, container_y, richText.width, richText.height);
      graphics.endFill();

//      const sprite = new PIXI.Sprite(texture);
      container.mask = graphics;

      return container
    },
    createText2: function () {
      const style = new PIXI.TextStyle({
        fontFamily: 'Arial',
        fontSize: 28,
//        lineHeight: 40,
        fontWeight: 'bold',
        fill: ['#03e1d1'], // gradient
        wordWrap: true,
        wordWrapWidth: 440,
//        padding: 20
      });

      const richText = new PIXI.Text('FITNESS', style);

      const container_x = (app.screen.width - richText.width) / 2;
      const container_y = 250;

      // 绘制背景
      const bg_color = new PIXI.Graphics();
      bg_color.beginFill(0x000000);
      bg_color.drawRect(0, 0, richText.width, richText.height);
      bg_color.endFill();
      let container = new PIXI.Container();


      container.addChild(bg_color);
      container.addChild(richText);
      container.x = container_x;
      container.y = container_y;


      const mask_graphics = new PIXI.Graphics();

      mask_graphics.lineStyle(4, 0xFF3300, 1);
      mask_graphics.beginFill(0x66CCFF);

//      mask_graphics.drawRect(container_x - 15, container_y, richText.width, richText.height);
      mask_graphics.drawRect(0, 0, richText.width, richText.height);


      mask_graphics.endFill();
      container.addChild(mask_graphics);

      container.mask = mask_graphics;
//      mask_graphics.x = 30;
//      mask_graphics.y = 30;

      mask_graphics.x = container.width / 2;
      mask_graphics.y = 0;
      mask_graphics.width = 0;

      const timer = setInterval(() => {
        mask_graphics.width = mask_graphics.width + 2;
        mask_graphics.x = (richText.width - mask_graphics.width) / 2;
        if (mask_graphics.width > richText.width) {
          clearInterval(timer)
        }
      }, 100);
      return container
    },
    createGeometry: function () {
      const geometry = new PIXI.Geometry()
        .addAttribute('aVertexPosition', // the attribute name
          [-1, -1, // x, y
            1, -1, // x, y
            -1, 1,
            1, 1], // x, y], // x, y
          2) // the size of the attribute

        .addAttribute('aColor', // the attribute name
          [1, 0, 0, // r, g, b
            0, 1, 0, // r, g, b
            0, 0, 1], // r, g, b
          3) // the size of the attribute

        .addIndex([0, 1, 2, 1, 2, 3]);

      const vertexSrc = `

 precision mediump float;
    attribute vec4 aVertexPosition;

    varying vec2 v_texCoord;
    void main()
    {
        gl_Position = aVertexPosition;
        // v_texCoord = aPosition;
        // v_texCoord = vec2((aVertexPosition.x), (1.0-aPosition.y));
        // 这是一种取巧的做法，强行把顶点坐标映射为纹理坐标，
        // 但是仅适用于本章用到的刚好占满整个viewport的顶点哦。
        v_texCoord = vec2((aVertexPosition.x+1.0)/2.0, 1.0-(aVertexPosition.y+1.0)/2.0);;
    }`;

//    const fragmentSrc = `
// precision mediump float;
//
// // the texCoords passed in from the vertex shader.
// varying vec2 v_texCoord;
//
// // our texture
// uniform sampler2D uSampler2;
//
// void main(){
//   // Look up a color from the texture.
//   gl_FragColor = texture2D(uSampler2, v_texCoord).bgra;
// }
//`;


      const uniforms = {
//      uSampler2: TextureCache[imgUrl],
        uSampler2: TextureCache[videoUrl],
//      steps: 1.0 / canvas.width, 1.0 / canvas.height,
        steps: uniforms_steps || [],
        time: 0,
      };

      const shader = PIXI.Shader.from(vertexSrc, fragmentSrc, uniforms);

      const triangle = new PIXI.Mesh(geometry, shader);
      triangle.position.set(400, 300);
      triangle.scale.set(2);

      return triangle;
    },
    // 滤镜发生改变
    filterChange: function () {
      this.startPlay()
    }
  };


  // 创建文字
  function createText(options) {
    let textItem = null;
    if (options.textType === 4) {
      textItem = new WeclipText4(options)
    } else if (options.textType === 1) {
      textItem = new WeclipText1(options)
    }
    return textItem
  }

  // 文字
  function WeclipText4(options = {}) {
    this.textType = options.textType; // 文字动画效果
    this.contain = null;             // 外层容器
    this.init = function () {
      this.contain = this.createText();
    };
    this.createText = function () {
      const style = new PIXI.TextStyle({
        fontFamily: 'Arial',
        fontSize: 36,
        fontWeight: 'bold',
        fill: ['#ffffff'], // gradient
        wordWrap: true,
        wordWrapWidth: 440,
      });

      const richText = new PIXI.Text('挑战你的极限', style);

      this.richText = richText;
      const container_x = (app.screen.width - richText.width) / 2;
      const container_y = 200;
      richText.x = 0;
      richText.y = -richText.height;
      let container = new PIXI.Container();
      container.addChild(richText);
      container.x = container_x;
      container.y = container_y;
//
//      const timer = setInterval(() => {
//        richText.y = richText.y + 2;
//        if (richText.y > 0) {
//          clearInterval(timer)
//        }
//      }, 70);


      const graphics = new PIXI.Graphics();
      graphics.beginFill(0xFF3300);
      graphics.drawRect(container_x, container_y, richText.width, richText.height);
      graphics.endFill();

//      const sprite = new PIXI.Sprite(texture);
      container.mask = graphics;

      return container
    };
    this.refreshView = function (currentTime) {
      // 存在
      const animationTime = 500;      // 动画过渡时间
      const startApearTime = 100;     // 出现动画时间
      const startDisApearTime = 2400;  // 消失动画时间
      if (currentTime >= startApearTime && currentTime <= (startDisApearTime + animationTime)) {
        this.contain.alpha = 1;
        const richText = this.richText;
        // 出现动画
        if (currentTime <= startApearTime + animationTime) {
          const percent = (currentTime - startApearTime) / animationTime;
          richText.y = -richText.height * (1 - percent);

        } else if (currentTime >= startDisApearTime) {      // 消失动画
          const percent = (currentTime - startDisApearTime) / animationTime;
          richText.y = -richText.height * percent;
        } else { // 出现完成

        }
      } else {
        this.contain.alpha = 0;
      }
    };
    this.init();
  }
  // 文字
  function WeclipText1(options = {}) {
    this.textType = options.textType; // 文字动画效果
    this.contain = null;             // 外层容器
    this.init = function () {
      this.contain = this.createText();
    };
    this.createText = function () {
      const style = new PIXI.TextStyle({
        fontFamily: 'Arial',
        fontSize: 28,
//        lineHeight: 40,
        fontWeight: 'bold',
        fill: ['#03e1d1'], // gradient
        wordWrap: true,
        wordWrapWidth: 440,
//        padding: 20
      });

      const richText = new PIXI.Text('FITNESS', style);

      this.richText = richText;
      const container_x = (app.screen.width - richText.width) / 2;
      const container_y = 250;

      // 绘制背景
      const bg_color = new PIXI.Graphics();
      bg_color.beginFill(0x000000);
      bg_color.drawRect(0, 0, richText.width, richText.height);
      bg_color.endFill();
      let container = new PIXI.Container();


      container.addChild(bg_color);
      container.addChild(richText);
      container.x = container_x;
      container.y = container_y;


      const mask_graphics = new PIXI.Graphics();
      this.mask_graphics = mask_graphics;
      mask_graphics.lineStyle(4, 0xFF3300, 1);
      mask_graphics.beginFill(0x66CCFF);

      mask_graphics.drawRect(0, 0, richText.width, richText.height);


      mask_graphics.endFill();
      container.addChild(mask_graphics);

      container.mask = mask_graphics;

      mask_graphics.x = container.width / 2;
      mask_graphics.y = 0;
      mask_graphics.width = 0;

//      const timer = setInterval(() => {
//        mask_graphics.width = mask_graphics.width + 2;
//        mask_graphics.x = (richText.width - mask_graphics.width) / 2;
//        if (mask_graphics.width > richText.width) {
//          clearInterval(timer)
//        }
//      }, 100);
      return container
    };
    this.refreshView = function (currentTime) {
      // 存在
      const animationTime = 500;      // 动画过渡时间
      const startApearTime = 200;     // 出现动画时间
      const startDisApearTime = 2300;  // 消失动画时间
      if (currentTime >= startApearTime && currentTime <= (startDisApearTime + animationTime)) {
        this.contain.alpha = 1;
        const richText = this.richText;
        const mask_graphics = this.mask_graphics;
//        mask_graphics.width = mask_graphics.width + 2;
//        mask_graphics.x = (richText.width - mask_graphics.width) / 2;
        // 出现动画
        if (currentTime <= startApearTime + animationTime) {
          const percent = (currentTime - startApearTime) / animationTime;

          mask_graphics.width = richText.width * percent;
          mask_graphics.x = (richText.width - mask_graphics.width) / 2;

        } else if (currentTime >= startDisApearTime) {      // 消失动画
          percent = (currentTime - startDisApearTime) / animationTime;
          mask_graphics.width = richText.width * (1 - percent);
          mask_graphics.x = (richText.width - mask_graphics.width) / 2;
        } else { // 出现完成

        }
      } else {
        this.contain.alpha = 0;
      }
    };
    this.init();
  }
  App.init();

  function startPlay() {
    App.startPlay()
  }
  function stopPlay() {
    App.stopPlay();
  }

  function playContinue() {
    if (videoTexture) {
      videoTexture.baseTexture.source.play();
    }
  }

</script>
</body>
</html>